package per.poker.chudadi;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.math.MathUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.paint.Color;
import javafx.stage.StageStyle;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
import per.poker.common.CommonService;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
import java.util.stream.Collectors;

import static per.poker.chudadi.CardValidator.*;

@Slf4j
public class ChudadiService extends ChudadiData {

    private Game game;
    private Thread thread = null;
    private int waitTime = 100;

    private final AtomicInteger count = new AtomicInteger(0);

    public void startGame() throws InterruptedException {

        CommonService.runLater(() -> {
            eastLabel.setText("东");
            westLabel.setText("西");
            southLabel.setText("南");
            northLabel.setText("北");
            stage.getChildren().clear();
        });
        count.set(0);

        discard.setDisable(true);
        pass.setDisable(true);
        thread = Thread.currentThread();
        boolean isPlain = game.getPlayerList().stream().allMatch(p -> p.getWinEnum() == null);
        //开局或平局
        if (isPlain) {
            for (Player player : game.getPlayerList()) {
                boolean ready = player.getCards().stream().anyMatch(c -> ObjectUtil.equal(c, "♦4"));
                player.setReady(ready);
            }
        } else {
            //交粮操作
            before();
            for (Player player : game.getPlayerList()) {
                player.setTurn(null);
                player.setWinEnum(null);
            }
        }
        give.setDisable(true);

        AtomicInteger idx = new AtomicInteger(0);
        while (game.getIsStarted()) {
            List<Player> playerList = game.getPlayerList();
            int index = idx.get() % 4;
            Player startPlayer = playerList.get(index);
            if (!startPlayer.getReady()) {
                idx.incrementAndGet();
                continue;
            }

            if (startPlayer.getFinished()) {
                startPlayer.setReady(false);
                int nextIndex = (idx.get() + 1) % 4;
                Player nextPlayer = playerList.get(nextIndex);
                nextPlayer.setReady(true);
                idx.incrementAndGet();
                continue;
            }

            if (end()) {
                break;
            }
            Thread.sleep(waitTime);
            log.info(StrUtil.format("————————轮到玩家 {}————————", startPlayer.getName()));
            print();

            Label label = new Label();
            label.setPrefWidth(670);
            label.setPrefHeight(36);
            label.setText(StrUtil.format("————————轮到玩家 {}————————", startPlayer.getName()));
            label.setAlignment(Pos.CENTER);
            Runnable turn = () -> {
                stage.getChildren().add(label);
                scrollPane.vvalueProperty().setValue(1.0);
            };
            CommonService.runLater(turn);

            if (ObjectUtil.equal(startPlayer.getName(), "south")) {

                boolean allPassed = game.getLastPlayer() == null && (count.get() == game.getPlayerList().stream().filter(c -> !c.getFinished()).count());
                boolean allSkiped = game.getLastPlayer() != null && ObjectUtil.equal(startPlayer.getName(), game.getLastPlayer().getName());
                if (allPassed || allSkiped) {
                    game.setLastPlayer(null);
                    game.getCards().clear();

                    log.info("————————玩家 {} 继续出牌————————", startPlayer.getName());
                    Label l = new Label();
                    l.setPrefWidth(670);
                    l.setPrefHeight(36);
                    l.setText(StrUtil.format("————————玩家 {} 继续出牌————————", startPlayer.getName()));
                    l.setAlignment(Pos.CENTER);
                    Runnable runnable = () -> {
                        stage.getChildren().add(l);
                        scrollPane.vvalueProperty().setValue(1.0);
                    };
                    CommonService.runLater(runnable);

                }
                //场上有牌才允许跳过
                pass.setDisable(game.getCards().isEmpty());

                discard.setDisable(false);
                LockSupport.park();

                startPlayer.setReady(false);
                //轮到下一个玩家
                int nextIndex = (idx.get() + 1) % 4;
                Player nextPlayer = playerList.get(nextIndex);
                nextPlayer.setReady(true);
                idx.incrementAndGet();
                //没牌就胜利
                if (startPlayer.getCards().isEmpty()) {
                    game.setLastPlayer(null);
                    int turns = (int) game.getPlayerList().stream().filter(Player::getFinished).count();
                    CommonService.runLater(() -> southLabel.setText(southLabel.getText() + "-" + turns));
                    startPlayer.setTurn(turns);
                    startPlayer.setFinished(true);
                }
                Thread.sleep(waitTime);
                continue;
            }

            boolean allPassed = game.getLastPlayer() == null && (count.get() == game.getPlayerList().stream().filter(c -> !c.getFinished()).count());
            boolean allSkiped = game.getLastPlayer() != null && ObjectUtil.equal(startPlayer.getName(), game.getLastPlayer().getName());
            if (allPassed || allSkiped) {
                game.setLastPlayer(null);
                game.getCards().clear();

                log.info("————————玩家 {} 继续出牌————————", startPlayer.getName());
                Label l = new Label();
                l.setPrefWidth(670);
                l.setPrefHeight(36);
                l.setText(StrUtil.format("————————玩家 {} 继续出牌————————", startPlayer.getName()));
                l.setAlignment(Pos.CENTER);
                Runnable runnable = () -> {
                    stage.getChildren().add(l);
                    scrollPane.vvalueProperty().setValue(1.0);
                };
                CommonService.runLater(runnable);

            }

            List<Node> selectedNodes = new LinkedList<>();
            //电脑自由出牌
            if (game.getCards().isEmpty()) {
                List<String> discards = freelyDiscard(startPlayer.getCards());
                selectedNodes.addAll(startPlayer.getPane().getChildren().stream()
                        .filter(e -> discards.contains(e.getId()))
                        .collect(Collectors.toList()));
            }
            //电脑压牌
            else {
                List<String> discards = discard(startPlayer.getCards());
                selectedNodes.addAll(startPlayer.getPane().getChildren().stream()
                        .filter(e -> discards.contains(e.getId()))
                        .collect(Collectors.toList()));
            }

            //跳过
            if (selectedNodes.isEmpty()) {
                log.info("————————玩家 {} 跳过————————", startPlayer.getName());

                Label l = new Label();
                l.setPrefWidth(670);
                l.setPrefHeight(36);
                l.setText(StrUtil.format("————————玩家 {} 跳过————————", startPlayer.getName()));
                l.setAlignment(Pos.CENTER);
                Runnable runnable = () -> {
                    stage.getChildren().add(l);
                    scrollPane.vvalueProperty().setValue(1.0);
                };
                CommonService.runLater(runnable);

                count.incrementAndGet();
            }
            //出牌
            else {
                Label l = new Label();
                l.setPrefWidth(670);
                l.setPrefHeight(36);
                l.setText(StrUtil.format("————————玩家 {} 出牌————————", startPlayer.getName()));
                l.setAlignment(Pos.CENTER);

                FlowPane flowPane = new FlowPane();
                flowPane.setPrefWidth(670);
                flowPane.setPrefHeight(114);

                for (Node node : selectedNodes) {

                    ImageView imageView = new ImageView();
                    imageView.setId(node.getId());
                    imageView.setFitWidth(53);
                    imageView.setFitHeight(75);
                    imageView.setPreserveRatio(true);
                    imageView.setPickOnBounds(true);

                    imageView.setImage(new Image(CommonService.getPicUrl("/img/" + node.getId() + ".jpg")));
                    flowPane.getChildren().add(imageView);
                }
                Runnable runnable = () -> {
                    stage.getChildren().add(l);
                    stage.getChildren().add(flowPane);
                    startPlayer.getPane().getChildren().removeAll(selectedNodes);
                    scrollPane.vvalueProperty().setValue(1.0);
                };
                CommonService.runLater(runnable);

                List<String> nodes = selectedNodes.stream().map(Node::getId).collect(Collectors.toList());
                if (nodes.contains("♠A")) {
                    CommonService.runLater(() -> startPlayer.getLabel().setText("♠A—" + startPlayer.getLabel().getText()));
                }
                if (nodes.contains("♠2")) {
                    CommonService.runLater(() -> startPlayer.getLabel().setText("♠2—" + startPlayer.getLabel().getText()));
                }

                startPlayer.getCards().removeAll(nodes);
                game.getCards().clear();
                game.getCards().addAll(nodes);
                game.setLastPlayer(startPlayer);

                count.set(0);
            }

            startPlayer.setReady(false);

            int nextIndex = (idx.get() + 1) % 4;
            Player nextPlayer = playerList.get(nextIndex);
            nextPlayer.setReady(true);
            idx.incrementAndGet();

            if (startPlayer.getCards().isEmpty()) {
                game.setLastPlayer(null);
                int turns = (int) game.getPlayerList().stream().filter(Player::getFinished).count();
                CommonService.runLater(() -> startPlayer.getLabel().setText(startPlayer.getLabel().getText() + "-" + turns));
                startPlayer.setTurn(turns);
                startPlayer.setFinished(true);
            }
            Thread.sleep(waitTime);

        }

    }

    private List<String> discard(List<String> playerCards) {
        List<String> decideCards = new ArrayList<>();
        for (String[] s : MathUtil.combinationSelect(
                ArrayUtil.toArray(playerCards, String.class), game.getCards().size())) {
            List<String> t = CollUtil.toList(s);
            if (isBigger(t, game.getCards()) == 1) {
                decideCards.addAll(t);
                return decideCards;
            }
        }
        return decideCards;
    }

    private List<String> freelyDiscard(List<String> cards) {
        List<String> decideCards = new ArrayList<>();
        if (cards.size() >= 5) {
            //自由出牌，优先出同花顺、顺子、三带二、四带一
            for (String[] s : MathUtil.combinationSelect(ArrayUtil.toArray(cards, String.class), 5)) {
                List<String> t = CollUtil.toList(s);
                if (isStraight(t)) {
                    decideCards.addAll(t);
                    return decideCards;
                }
            }
            for (String[] s : MathUtil.combinationSelect(ArrayUtil.toArray(cards, String.class), 5)) {
                List<String> t = CollUtil.toList(s);
                if (isFlush(t)) {
                    decideCards.addAll(t);
                    return decideCards;
                }
            }
            for (String[] s : MathUtil.combinationSelect(ArrayUtil.toArray(cards, String.class), 5)) {
                List<String> t = CollUtil.toList(s);
                if (is3N2(t)) {
                    if (disCardSmallFirstly(cards, decideCards, t)) {
                        return decideCards;
                    }

                }
            }
            for (String[] s : MathUtil.combinationSelect(ArrayUtil.toArray(cards, String.class), 5)) {
                List<String> t = CollUtil.toList(s);
                if (is4N1(t)) {
                    if (disCardSmallFirstly(cards, decideCards, t)) {
                        return decideCards;
                    }
                }
            }
        }

        for (String[] s : MathUtil.combinationSelect(ArrayUtil.toArray(cards, String.class), 4)) {
            List<String> t = CollUtil.toList(s);
            if (isQuadruple(cards)) {
                CardEnum mainCard = EnumUtil.getBy(CardEnum.class, c ->
                        ObjectUtil.equals(c.getCode(), Objects.requireNonNull(getMainCard(t)).substring(1)));
                if (mainCard.getNum() > 11 && cards.size() < 8) {
                    decideCards.addAll(t);
                    return decideCards;
                } else if (mainCard.getNum() <= 11) {
                    decideCards.addAll(t);
                    return decideCards;
                }

            }
        }

        for (String[] s : MathUtil.combinationSelect(ArrayUtil.toArray(cards, String.class), 3)) {
            List<String> t = CollUtil.toList(s);
            if (isTriple(t)) {
                CardEnum mainCard = EnumUtil.getBy(CardEnum.class, c ->
                        ObjectUtil.equals(c.getCode(), Objects.requireNonNull(getMainCard(t)).substring(1)));
                if (mainCard.getNum() > 11 && cards.size() < 8) {
                    decideCards.addAll(t);
                    return decideCards;
                } else if (mainCard.getNum() <= 11) {
                    decideCards.addAll(t);
                    return decideCards;
                }

            }
        }

        for (String[] s : MathUtil.combinationSelect(ArrayUtil.toArray(cards, String.class), 2)) {
            List<String> t = CollUtil.toList(s);
            if (isPair(t)) {
                CardEnum mainCard = EnumUtil.getBy(CardEnum.class, c ->
                        ObjectUtil.equals(c.getCode(), Objects.requireNonNull(getMainCard(t)).substring(1)));
                if (mainCard.getNum() > 11 && cards.size() < 8) {
                    decideCards.addAll(t);
                    return decideCards;
                } else if (mainCard.getNum() <= 11) {
                    decideCards.addAll(t);
                    return decideCards;
                }

            }
        }

        decideCards.add(cards.get(0));
        return decideCards;
    }

    private boolean disCardSmallFirstly(List<String> cards, List<String> decideCards, List<String> t) {
        CardEnum mainCard = EnumUtil.getBy(CardEnum.class, c ->
                ObjectUtil.equals(c.getCode(), Objects.requireNonNull(getMainCard(t)).substring(1)));
        if (mainCard.getNum() > 11 && cards.size() < 8) {
            decideCards.addAll(t);
            return true;
        } else if (mainCard.getNum() <= 11) {
            decideCards.addAll(t);
            return true;
        }
        return false;
    }


    /*void debug() {
        game.getPlayerList().get(1).setWinEnum(WinEnum.GIV_ONE);
        game.getPlayerList().get(1).setTurn(3);

        game.getPlayerList().get(0).setWinEnum(WinEnum.GIV_ONE);
        game.getPlayerList().get(2).setWinEnum(WinEnum.REC_ONE);
        game.getPlayerList().get(3).setWinEnum(WinEnum.REC_ONE);

        game.getPlayerList().get(0).setTurn(2);
        game.getPlayerList().get(2).setTurn(0);
        game.getPlayerList().get(3).setTurn(1);
    }*/

    private void before() throws InterruptedException {

        if (playerRec3()) {
            return;
        } else if (playerGiv3()) {
            return;
        }
        playerRecGiv();
    }

    private boolean playerRec3() throws InterruptedException {
        Optional<Player> op = game.getPlayerList().stream()
                .filter(p -> p.getWinEnum() == WinEnum.REC_THREE).findFirst();
        if (op.isPresent()) {

            //交粮
            Map<String, String> recCards = new HashMap<>(4);
            //按上局胜利顺序排序
            List<Player> gives = game.getPlayerList().stream()
                    .filter(p -> p.getWinEnum() == WinEnum.GIV_ONE)
                    .sorted(Comparator.comparingInt(Player::getTurn))
                    .collect(Collectors.toList());

            //先给玩家
            for (Player player : gives) {
                Label l = new Label();
                l.setPrefWidth(670);
                l.setPrefHeight(36);
                l.setText(StrUtil.format("————————玩家 {} 向 {} 交粮————————", player.getName(), op.get().getName()));
                l.setAlignment(Pos.CENTER);

                FlowPane flowPane = new FlowPane();
                flowPane.setPrefWidth(670);
                flowPane.setPrefHeight(114);

                //跳过身份牌拿一张最大的
                String card = null;
                for (int i = player.getCards().size() - 1; i >= 0; i--) {
                    if (ObjectUtil.notEqual(player.getCards().get(i), "♠2") && ObjectUtil.notEqual(player.getCards().get(i), "♠A")) {
                        card = player.getCards().get(i);
                        break;
                    }
                }
                ImageView imageView = new ImageView();
                imageView.setId(card);
                imageView.setFitWidth(53);
                imageView.setFitHeight(75);
                imageView.setPreserveRatio(true);
                imageView.setPickOnBounds(true);

                imageView.setImage(new Image(CommonService.getPicUrl("/img/" + card + ".jpg")));
                flowPane.getChildren().add(imageView);

                String finalCard = card;
                Node node = player.getPane().getChildren().stream()
                        .filter(p -> ObjectUtil.equals(finalCard, p.getId())).findFirst().get();
                Runnable runnable = () -> {
                    stage.getChildren().add(l);
                    stage.getChildren().add(flowPane);
                    player.getPane().getChildren().remove(node);
                    scrollPane.vvalueProperty().setValue(1.0);
                };
                CommonService.runLater(runnable);
                player.getCards().remove(card);
                recCards.put(player.getName(), card);
            }

            //玩家再回
            Label l = new Label();
            l.setPrefWidth(670);
            l.setPrefHeight(36);
            l.setText(StrUtil.format("————————轮到{} 给牌,收粮玩家可以点击选择————————", op.get().getName()));
            l.setAlignment(Pos.CENTER);
            CommonService.runLater(() -> {
                stage.getChildren().add(l);
                scrollPane.vvalueProperty().setValue(1.0);
            });

            List<Node> backList = new LinkedList<>();
            if (ObjectUtil.equals(op.get().getName(), "south")) {
                give.setDisable(false);
                LockSupport.park();
                backList.addAll(game.getPlayerList().get(1).getPane().getChildren()
                        .stream().filter(c -> c.getEffect() != null).collect(Collectors.toList()));
            } else {
                backList.addAll(op.get().getPane().getChildren().subList(0, 3));
            }

            FlowPane flowPane = new FlowPane();
            flowPane.setPrefWidth(670);
            flowPane.setPrefHeight(114);

            for (Node back : backList) {
                ImageView imageView = new ImageView();
                imageView.setId(back.getId());
                imageView.setFitWidth(53);
                imageView.setFitHeight(75);
                imageView.setPreserveRatio(true);
                imageView.setPickOnBounds(true);
                imageView.setImage(new Image(CommonService.getPicUrl("/img/" + back.getId() + ".jpg")));
                flowPane.getChildren().add(imageView);

                if (ObjectUtil.notEqual("south", op.get().getName())) {
                    imageView.setOnMouseClicked(e -> {
                        if (imageView.getEffect() == null) {
                            imageView.setEffect(new DropShadow(15, Color.YELLOW));
                        } else {
                            imageView.setEffect(null);
                        }

                        LockSupport.unpark(thread);
                    });
                }
            }
            CommonService.runLater(() -> {
                stage.getChildren().add(flowPane);
                op.get().getPane().getChildren().removeAll(backList);
                scrollPane.vvalueProperty().setValue(1.0);
            });

            List<String> backCards = backList.stream().map(Node::getId)
                    .sorted(CardValidator::isBigger).collect(Collectors.toList());

            op.get().getCards().removeAll(backCards);

            for (Player player : gives) {

                String takenCard;
                if (ObjectUtil.equals(player.getName(), "south")) {
                    LockSupport.park();

                    takenCard = flowPane.getChildren().stream()
                            .filter(e -> e.getEffect() != null).findFirst().get().getId();
                    for (Node child : flowPane.getChildren()) {
                        child.setOnMouseClicked(null);
                        child.setEffect(null);
                    }
                } else {
                    takenCard = CollUtil.getLast(backCards);
                }

                //给回去的牌
                player.getCards().add(takenCard);
                log.info("玩家 {} 拿走了 {}", player.getName(), takenCard);

                Label k = new Label();
                k.setPrefWidth(670);
                k.setPrefHeight(36);
                k.setText(StrUtil.format("玩家 {} 拿走了 {}", player.getName(), takenCard));
                k.setAlignment(Pos.CENTER);
                CommonService.runLater(() -> {
                    stage.getChildren().add(k);
                    scrollPane.vvalueProperty().setValue(1.0);
                });

                backCards.remove(takenCard);
            }

            //给最大的牌的玩家先出
            String biggestCard = recCards.values().stream().sorted(CardValidator::isBigger)
                    .collect(Collectors.toList()).get(2);
            AtomicReference<String> name = new AtomicReference<>();
            recCards.forEach((k, v) -> {
                if (ObjectUtil.equals(v, biggestCard)) {
                    name.set(k);
                }
            });

            op.get().getCards().addAll(recCards.values());

            Map<String, List<String>> cards = new HashMap<>(8);
            for (Player player : game.getPlayerList()) {
                player.getCards().sort(CardValidator::isBigger);
                cards.put(player.getName(), player.getCards());
                CommonService.runLater(() -> player.getPane().getChildren().clear());
            }
            CommonService.runLater(() -> showCard(cards));

            game.getPlayerList().stream()
                    .filter(p -> ObjectUtil.equals(name.get(), p.getName())).findFirst()
                    .get().setReady(true);

            return true;
        }

        return false;
    }

    private boolean playerGiv3() throws InterruptedException {

        Optional<Player> op = game.getPlayerList().stream()
                .filter(p -> p.getWinEnum() == WinEnum.GIV_THREE).findFirst();
        if (op.isPresent()) {

            //玩家收到的
            List<String> recCards = new LinkedList<>();

            List<String> giveCards = new LinkedList<>();
            for (int i = op.get().getCards().size() - 1; i >= 0; i--) {

                if (ObjectUtil.notEqual(op.get().getCards().get(i), "♠2") &&
                        ObjectUtil.notEqual(op.get().getCards().get(i), "♠A")) {

                    giveCards.add(op.get().getCards().get(i));

                    if (giveCards.size() == 3) {
                        break;
                    }
                }
            }

            List<Player> gives = game.getPlayerList().stream()
                    .filter(p -> p.getWinEnum() == WinEnum.REC_ONE)
                    .sorted(Comparator.comparingInt(Player::getTurn))
                    .collect(Collectors.toList());

            //先给玩家
            for (Player player : gives) {
                Label l = new Label();
                l.setPrefWidth(670);
                l.setPrefHeight(36);
                l.setText(StrUtil.format("————————玩家 {} 给 {} 牌————————", player.getName(), op.get().getName()));
                l.setAlignment(Pos.CENTER);

                FlowPane flowPane = new FlowPane();
                flowPane.setPrefWidth(670);
                flowPane.setPrefHeight(114);

                String card;
                if (ObjectUtil.equals(player.getName(), "south")) {
                    give.setDisable(false);
                    LockSupport.park();
                    card = player.getPane().getChildren().stream()
                            .filter(e -> e.getEffect() != null).findFirst().get().getId();
                } else {
                    card = player.getCards().get(0);
                }

                ImageView imageView = new ImageView();
                imageView.setId(card);
                imageView.setFitWidth(53);
                imageView.setFitHeight(75);
                imageView.setPreserveRatio(true);
                imageView.setPickOnBounds(true);

                imageView.setImage(new Image(CommonService.getPicUrl("/img/" + card + ".jpg")));
                flowPane.getChildren().add(imageView);

                Node node = player.getPane().getChildren().stream()
                        .filter(p -> ObjectUtil.equals(card, p.getId())).findFirst().get();
                Runnable runnable = () -> {
                    stage.getChildren().add(l);
                    stage.getChildren().add(flowPane);
                    player.getPane().getChildren().remove(node);
                    scrollPane.vvalueProperty().setValue(1.0);
                };
                CommonService.runLater(runnable);
                player.getCards().remove(card);

                recCards.add(card);
            }

            //玩家再回
            Label l = new Label();
            l.setPrefWidth(670);
            l.setPrefHeight(36);
            l.setText(StrUtil.format("————————{} 给牌,收粮玩家可以点击选择————————", op.get().getName()));
            l.setAlignment(Pos.CENTER);

            FlowPane flowPane = new FlowPane();
            flowPane.setPrefWidth(670);
            flowPane.setPrefHeight(114);
            for (String c : giveCards) {
                ImageView imageView = new ImageView();
                imageView.setId(c);
                imageView.setFitWidth(53);
                imageView.setFitHeight(75);
                imageView.setPreserveRatio(true);
                imageView.setPickOnBounds(true);
                imageView.setImage(new Image(CommonService.getPicUrl("/img/" + c + ".jpg")));
                flowPane.getChildren().add(imageView);
                op.get().getCards().remove(c);

                if (ObjectUtil.notEqual("south", op.get().getName())) {
                    imageView.setOnMouseClicked(e -> {
                        if (imageView.getEffect() == null) {
                            imageView.setEffect(new DropShadow(15, Color.YELLOW));
                        } else {
                            imageView.setEffect(null);
                        }

                        LockSupport.unpark(thread);
                    });
                }
            }

            List<Node> back = op.get().getPane().getChildren()
                    .stream().filter(c -> c.getEffect() != null).collect(Collectors.toList());
            CommonService.runLater(() -> {
                stage.getChildren().add(l);
                stage.getChildren().add(flowPane);
                op.get().getPane().getChildren().removeAll(back);
                scrollPane.vvalueProperty().setValue(1.0);
            });

            //给回去的牌
            for (Player player : gives) {

                String takenCard;
                if (ObjectUtil.equals(player.getName(), "south")) {
                    LockSupport.park();

                    takenCard = flowPane.getChildren().stream()
                            .filter(e -> e.getEffect() != null).findFirst().get().getId();
                    for (Node child : flowPane.getChildren()) {
                        child.setOnMouseClicked(null);
                        child.setEffect(null);
                    }
                } else {
                    takenCard = giveCards.get(0);
                }

                //给回去的牌
                player.getCards().add(takenCard);
                log.info("玩家 {} 拿走了 {}", player.getName(), takenCard);

                Label k = new Label();
                k.setPrefWidth(670);
                k.setPrefHeight(36);
                k.setText(StrUtil.format("玩家 {} 拿走了 {}", player.getName(), takenCard));
                k.setAlignment(Pos.CENTER);
                CommonService.runLater(() -> {
                    stage.getChildren().add(k);
                    scrollPane.vvalueProperty().setValue(1.0);
                });

                giveCards.remove(takenCard);
            }

            op.get().getCards().addAll(recCards);

            Map<String, List<String>> cards = new HashMap<>(8);
            for (Player player : game.getPlayerList()) {
                player.getCards().sort(CardValidator::isBigger);
                cards.put(player.getName(), player.getCards());
                CommonService.runLater(() -> player.getPane().getChildren().clear());
            }
            CommonService.runLater(() -> showCard(cards));

            game.getPlayerList().stream()
                    .filter(p -> ObjectUtil.equals(op.get().getName(), p.getName())).findFirst()
                    .get().setReady(true);
            return true;
        }
        return false;
    }

    private void playerRecGiv() throws InterruptedException {
        //平民或地主全部获胜
        List<Player> winners = game.getPlayerList().stream()
                .filter(p -> p.getWinEnum() == WinEnum.REC_ONE)
                .sorted(Comparator.comparingInt(Player::getTurn)).collect(Collectors.toList());

        List<Player> losers = game.getPlayerList().stream()
                .filter(p -> p.getWinEnum() == WinEnum.GIV_ONE)
                .sorted(Comparator.comparingInt(Player::getTurn)).collect(Collectors.toList());

        //交粮
        Map<String, String> recCards = new HashMap<>(4);
        List<Node> giveList = new LinkedList<>();
        List<Node> backList = new LinkedList<>();

        //输家先交粮
        for (Player player : losers) {

            StringBuilder sb = new StringBuilder("————————玩家 {} 交粮");
            if (winners.stream().anyMatch(p -> ObjectUtil.equal(p.getName(), "south")) &&
                    winners.stream().filter(p -> ObjectUtil.equal(p.getName(), "south"))
                            .findFirst().get().getTurn() == 0) {
                sb.append(",收粮玩家可以点击选择");
            }
            sb.append("————————");
            Label l = new Label();
            l.setPrefWidth(670);
            l.setPrefHeight(36);
            l.setText(StrUtil.format(sb.toString(), player.getName()));
            l.setAlignment(Pos.CENTER);

            FlowPane flowPane = new FlowPane();
            flowPane.setPrefWidth(670);
            flowPane.setPrefHeight(114);

            //跳过身份牌拿一张最大的
            String card = null;
            for (int i = player.getCards().size() - 1; i >= 0; i--) {
                if (ObjectUtil.notEqual(player.getCards().get(i), "♠2") && ObjectUtil.notEqual(player.getCards().get(i), "♠A")) {
                    card = player.getCards().get(i);
                    break;
                }
            }
            ImageView imageView = new ImageView();
            imageView.setId(card);
            imageView.setFitWidth(53);
            imageView.setFitHeight(75);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/" + card + ".jpg")));
            flowPane.getChildren().add(imageView);

            String finalCard = card;
            Node node = player.getPane().getChildren().stream()
                    .filter(p -> ObjectUtil.equals(finalCard, p.getId())).findFirst().get();

            Runnable runnable = () -> {
                stage.getChildren().add(l);
                stage.getChildren().add(flowPane);
                player.getPane().getChildren().remove(node);
                scrollPane.vvalueProperty().setValue(1.0);
            };
            CommonService.runLater(runnable);
            player.getCards().remove(card);
            recCards.put(player.getName(), card);

            giveList.add(imageView);
        }

        //赢家给粮
        for (Player player : winners) {

            StringBuilder sb = new StringBuilder("————————轮到{} 给牌");
            //玩家是最后一名的话就无法挑粮
            if (losers.stream().anyMatch(p -> ObjectUtil.equal(p.getName(), "south")) &&
                    losers.stream().filter(p -> ObjectUtil.equal(p.getName(), "south"))
                            .findFirst().get().getTurn() != 3) {
                sb.append(",收粮玩家可以点击选择");
            }
            sb.append("————————");

            Label l = new Label();
            l.setPrefWidth(670);
            l.setPrefHeight(36);
            l.setText(StrUtil.format(sb.toString(), player.getName()));
            l.setAlignment(Pos.CENTER);
            CommonService.runLater(() -> {
                stage.getChildren().add(l);
                scrollPane.vvalueProperty().setValue(1.0);
            });

            Node back;
            if (ObjectUtil.equals(player.getName(), "south")) {
                give.setDisable(false);
                LockSupport.park();
                back = player.getPane().getChildren()
                        .stream().filter(c -> c.getEffect() != null).findFirst().get();
            } else {
                back = player.getPane().getChildren().get(0);
            }

            FlowPane flowPane = new FlowPane();
            flowPane.setPrefWidth(670);
            flowPane.setPrefHeight(114);

            ImageView imageView = new ImageView();
            imageView.setId(back.getId());
            imageView.setFitWidth(53);
            imageView.setFitHeight(75);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);
            imageView.setImage(new Image(CommonService.getPicUrl("/img/" + back.getId() + ".jpg")));
            flowPane.getChildren().add(imageView);

            if (losers.stream().anyMatch(e -> ObjectUtil.equal(e.getName(), "south")) &&
                    losers.stream().filter(p -> ObjectUtil.equal(p.getName(), "south"))
                            .findFirst().get().getTurn() != 3) {
                imageView.setOnMouseClicked(e -> {
                    if (imageView.getEffect() == null) {
                        imageView.setEffect(new DropShadow(15, Color.YELLOW));
                    } else {
                        imageView.setEffect(null);
                    }

                    LockSupport.unpark(thread);
                });
            }

            CommonService.runLater(() -> {
                stage.getChildren().add(flowPane);
                player.getPane().getChildren().remove(back);
                scrollPane.vvalueProperty().setValue(1.0);
            });

            player.getCards().remove(back.getId());
            backList.add(imageView);
        }

        giveList.sort((o1, o2) -> CardValidator.isBigger(o1.getId(), o2.getId()));
        backList.sort((o1, o2) -> CardValidator.isBigger(o1.getId(), o2.getId()));

        Optional<Player> ownOp = winners.stream().filter(e -> ObjectUtil.equal("south", e.getName())).findFirst();
        if (ownOp.isPresent()) {
            //只有排名第一才能挑粮
            if (ownOp.get().getTurn() == 0) {
                for (Node node : giveList) {
                    node.setOnMouseClicked(e -> {
                        node.setEffect(new DropShadow(15, Color.YELLOW));
                        LockSupport.unpark(thread);
                    });
                }
            }
        }
        //赢家挑粮
        for (Player player : winners) {

            String takenCard;
            if (ObjectUtil.equals(player.getName(), "south") && player.getTurn() == 0) {
                LockSupport.park();

                Node takeNode = giveList.stream().filter(e -> e.getEffect() != null).findFirst().get();
                for (Node child : giveList) {
                    child.setOnMouseClicked(null);
                    child.setEffect(null);
                }
                takenCard = takeNode.getId();
                giveList.remove(takeNode);

            } else {
                Node takeNode = CollUtil.getLast(giveList);
                takenCard = takeNode.getId();
                giveList.remove(takeNode);
            }

            //给回去的牌
            player.getCards().add(takenCard);
            log.info("玩家 {} 拿走了 {}", player.getName(), takenCard);

            Label k = new Label();
            k.setPrefWidth(670);
            k.setPrefHeight(36);
            k.setText(StrUtil.format("玩家 {} 拿走了 {}", player.getName(), takenCard));
            k.setAlignment(Pos.CENTER);
            CommonService.runLater(() -> {
                stage.getChildren().add(k);
                scrollPane.vvalueProperty().setValue(1.0);
            });

        }

        //输家收粮
        for (Player player : losers) {

            String takenCard;
            //最后一名就无法挑粮
            if (ObjectUtil.equals(player.getName(), "south") && player.getTurn() != 3) {
                LockSupport.park();

                Node takeNode = backList.stream().filter(e -> e.getEffect() != null).findFirst().get();
                for (Node child : backList) {
                    child.setOnMouseClicked(null);
                    child.setEffect(null);
                }
                takenCard = takeNode.getId();
                backList.remove(takeNode);

            } else {
                Node takeNode = CollUtil.getLast(backList);
                takenCard = takeNode.getId();
                backList.remove(takeNode);
            }

            //给回去的牌
            player.getCards().add(takenCard);
            log.info("玩家 {} 拿走了 {}", player.getName(), takenCard);

            Label k = new Label();
            k.setPrefWidth(670);
            k.setPrefHeight(36);
            k.setText(StrUtil.format("玩家 {} 拿走了 {}", player.getName(), takenCard));
            k.setAlignment(Pos.CENTER);
            CommonService.runLater(() -> {
                stage.getChildren().add(k);
                scrollPane.vvalueProperty().setValue(1.0);
            });

        }


        //给最大的牌的玩家先出
        String biggestCard = CollUtil.getLast(recCards.values().stream().sorted(CardValidator::isBigger)
                .collect(Collectors.toList()));
        AtomicReference<String> name = new AtomicReference<>();
        recCards.forEach((k, v) -> {
            if (ObjectUtil.equals(v, biggestCard)) {
                name.set(k);
            }
        });


        Map<String, List<String>> cards = new HashMap<>(8);
        for (Player player : game.getPlayerList()) {
            player.getCards().sort(CardValidator::isBigger);
            cards.put(player.getName(), player.getCards());
            CommonService.runLater(() -> player.getPane().getChildren().clear());
        }
        CommonService.runLater(() -> showCard(cards));

        game.getPlayerList().stream()
                .filter(p -> ObjectUtil.equals(name.get(), p.getName())).findFirst()
                .get().setReady(true);
    }

    public void initButton() {
        discard.setOnMouseClicked(e -> {

            List<Node> selectedNodes = south.getChildren().stream()
                    .filter(c -> c.getEffect() != null)
                    .collect(Collectors.toList());
            if (selectedNodes.isEmpty()) {
                CommonService.errorDialog("未选择要出的牌");
                return;
            }

            List<String> cards = selectedNodes.stream().map(Node::getId).collect(Collectors.toList());
            if (CardValidator.getMainCard(cards) == null) {
                CommonService.errorDialog("错误的牌");
                return;
            }
            //自己出牌
            if (game.getCards().isEmpty()) {
                log.info("玩家  south  出牌");
            }
            //压牌
            else {

                String lastCard = CardValidator.getMainCard(game.getCards());
                String ownCard = CardValidator.getMainCard(cards);

                if (game.getCards().size() != cards.size()) {
                    CommonService.errorDialog("错误的牌");
                    return;
                }
                if (CardValidator.isBigger(ownCard, lastCard) == 1) {
                    log.info("玩家  south  出牌");
                } else if (CardValidator.isBigger(ownCard, lastCard) == -1) {
                    CommonService.errorDialog("出的牌太小");
                    return;
                } else {
                    CommonService.errorDialog("错误的牌");
                    return;
                }

            }

            Label label = new Label();
            label.setPrefWidth(670);
            label.setPrefHeight(36);
            label.setText(StrUtil.format("————————玩家 south 出牌————————"));
            label.setAlignment(Pos.CENTER);

            FlowPane flowPane = new FlowPane();
            flowPane.setPrefWidth(670);
            flowPane.setPrefHeight(114);
            for (Node node : selectedNodes) {
                ImageView imageView = new ImageView();
                imageView.setId(node.getId());
                imageView.setFitWidth(53);
                imageView.setFitHeight(75);
                imageView.setPreserveRatio(true);
                imageView.setPickOnBounds(true);

                imageView.setImage(new Image(CommonService.getPicUrl("/img/" + node.getId() + ".jpg")));
                flowPane.getChildren().add(imageView);
            }

            stage.getChildren().add(label);
            stage.getChildren().add(flowPane);
            south.getChildren().removeAll(selectedNodes);
            scrollPane.vvalueProperty().setValue(1.0);

            List<String> nodes = selectedNodes.stream().map(Node::getId).collect(Collectors.toList());
            if (nodes.contains("♠A")) {
                southLabel.setText("♠A—" + southLabel.getText());
            }
            if (nodes.contains("♠2")) {
                southLabel.setText("♠2—" + southLabel.getText());
            }
            game.getPlayerList().get(1).getCards().removeAll(nodes);
            game.getCards().clear();
            game.getCards().addAll(nodes);
            game.setLastPlayer(game.getPlayerList().get(1));

            count.set(0);
            LockSupport.unpark(thread);

        });
        pass.setOnMouseClicked(e -> {
            log.info("玩家 south 跳过");
            Label label = new Label();
            label.setPrefWidth(670);
            label.setPrefHeight(36);
            label.setText(StrUtil.format("————————玩家 south 跳过————————"));
            label.setAlignment(Pos.CENTER);
            stage.getChildren().add(label);

            count.incrementAndGet();
            discard.setDisable(true);
            pass.setDisable(true);
            LockSupport.unpark(thread);
        });
        give.setOnMouseClicked(e -> {
            List<Node> selectedNodes = south.getChildren().stream()
                    .filter(c -> c.getEffect() != null)
                    .collect(Collectors.toList());
            if (selectedNodes.isEmpty()) {
                CommonService.errorDialog("未选择要给的牌");
                return;
            }
            if (CollUtil.containsAny(selectedNodes.stream().map(Node::getId).collect(Collectors.toList()),
                    CollUtil.newArrayList("♠A", "♠2"))) {
                CommonService.errorDialog("身份牌不能给");
                return;
            }

            if (game.getPlayerList().get(1).getWinEnum() == WinEnum.REC_THREE) {
                if (selectedNodes.size() != 3) {
                    CommonService.errorDialog("给的牌要凑够三张");
                    return;
                }
            }

            give.setDisable(true);
            LockSupport.unpark(thread);
        });
    }

    public void showCard(Map<String, List<String>> cards) {

        south.getChildren().clear();
        north.getChildren().clear();
        east.getChildren().clear();
        west.getChildren().clear();

        for (String s : cards.get("south")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(53);
            imageView.setFitHeight(75);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/" + s + ".jpg")));
            south.getChildren().add(imageView);
            imageView.setOnMouseClicked(e -> {
                if (imageView.getEffect() == null) {
                    if (south.getChildren().stream().filter(c -> c.getEffect() != null).count() == 5) {
                        CommonService.errorDialog("出牌不能超过5张");
                        return;
                    }
                    imageView.setEffect(new DropShadow(15, Color.LIGHTSKYBLUE));
                } else {
                    imageView.setEffect(null);
                }
            });
        }

        for (String s : cards.get("north")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(53);
            imageView.setFitHeight(75);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/vertical.jpg")));
            north.getChildren().add(imageView);
        }

        for (String s : cards.get("east")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(75);
            imageView.setFitHeight(53);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/horizontal.jpg")));
            east.getChildren().add(imageView);
        }

        for (String s : cards.get("west")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(75);
            imageView.setFitHeight(53);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/horizontal.jpg")));
            west.getChildren().add(imageView);
        }

        List<Player> playerList = new ArrayList<>(8);

        playerList.add(getPlayer(0, cards));
        playerList.add(getPlayer(1, cards));
        playerList.add(getPlayer(2, cards));
        playerList.add(getPlayer(3, cards));

        game = new Game(playerList, Boolean.TRUE, new LinkedList<>(), null);
    }

    private Player getPlayer(int idx, Map<String, List<String>> cards) {
        switch (idx) {
            case 0:
                return new Player("east", cards.get("east"), false, false,
                        east, judgeRole(cards.get("east")),
                        game != null ? game.getPlayerList().get(0).getTurn() : null,
                        game != null ? game.getPlayerList().get(0).getWinEnum() : null, eastLabel);
            case 1:
                return new Player("south", cards.get("south"), false, false,
                        south, judgeRole(cards.get("south")),
                        game != null ? game.getPlayerList().get(1).getTurn() : null,
                        game != null ? game.getPlayerList().get(1).getWinEnum() : null, southLabel);
            case 2:
                return new Player("west", cards.get("west"), false, false,
                        west, judgeRole(cards.get("west")),
                        game != null ? game.getPlayerList().get(2).getTurn() : null,
                        game != null ? game.getPlayerList().get(2).getWinEnum() : null, westLabel);
            case 3:
                return new Player("north", cards.get("north"), false, false,
                        north, judgeRole(cards.get("north")),
                        game != null ? game.getPlayerList().get(3).getTurn() : null,
                        game != null ? game.getPlayerList().get(3).getWinEnum() : null, northLabel);
            default:
                return null;
        }
    }

    private RoleEnum judgeRole(List<String> cards) {
        if (cards.contains("♠2") && cards.contains("♠A")) {
            return RoleEnum.SPECIAL_TWO;
        } else if (cards.contains("♠2") || cards.contains("♠A")) {
            return RoleEnum.SPECIAL_ONE;
        } else {
            return RoleEnum.NORMAL;
        }
    }

    private void print() throws InterruptedException {
        for (Player player : game.getPlayerList()) {
            StringBuilder sb = new StringBuilder("[");
            if (!player.getFinished()) {
                log.info("{} 实际卡牌：{}", player.getName(), player.getCards());

                for (Node child : player.getPane().getChildren()) {
                    sb.append(child.getId()).append(", ");
                }
                if (sb.length() > 2) {
                    sb.delete(sb.length() - 2, sb.length());
                }
                log.info("{} 拥有卡牌：{}", player.getName(), sb.append("]"));
                int counter = 0;
                while (player.getPane().getChildren().size() != player.getCards().size()) {
                    if (counter < 10) {
                        Thread.sleep(1000);
                        counter++;
                        continue;
                    }
                    throw new RuntimeException(StrUtil.format("error {}", player.getName()));
                }
            }
        }
    }

    private boolean end() throws InterruptedException {

        List<Player> winner = game.getPlayerList().stream().filter(Player::getFinished).collect(Collectors.toList());
        if (winner.size() == 1) {
            if (winner.get(0).getRole() == RoleEnum.SPECIAL_TWO) {
                winner.get(0).setWinEnum(WinEnum.REC_THREE);
                game.getPlayerList().stream().filter(p -> !p.getFinished()).forEach(p -> p.setWinEnum(WinEnum.GIV_ONE));

                AtomicInteger turns = new AtomicInteger(1);
                game.getPlayerList().stream()
                        .filter(p -> !p.getFinished()).sorted(Comparator.comparingInt(o -> o.getCards().size()))
                        .forEach(p -> p.setTurn(turns.getAndIncrement()));

                List<Player> ls = game.getPlayerList().stream().filter(p -> !p.getFinished()).collect(Collectors.toList());
                List<String> losers = ls.stream().map(Player::getName).collect(Collectors.toList());
                log.info("游戏结束,没身份牌的玩家 {} 败北", losers);
                game.setIsStarted(false);
                Runnable r = () -> dialog(StrUtil.format("游戏结束,没身份牌的玩家 {} 败北", losers));
                CommonService.runLater(r);
                return true;
            }
        }

        if (winner.size() == 2) {

            boolean sp = winner.stream().anyMatch(p -> p.getRole() == RoleEnum.SPECIAL_TWO);
            //有两个身份牌玩家的情况下，已经有两个平民胜利的话会走这里，所以排除
            if (winner.stream().allMatch(p -> p.getRole() == RoleEnum.NORMAL) && !sp) {
                winner.stream().filter(p -> p.getTurn() == 0).findFirst().get().setWinEnum(WinEnum.REC_ONE);
                winner.stream().filter(p -> p.getTurn() == 1).findFirst().get().setWinEnum(WinEnum.REC_ONE);
                game.getPlayerList().stream().filter(p -> !p.getFinished()).forEach(p -> p.setWinEnum(WinEnum.GIV_ONE));

                AtomicInteger turns = new AtomicInteger(2);
                game.getPlayerList().stream()
                        .filter(p -> !p.getFinished()).sorted(Comparator.comparingInt(o -> o.getCards().size()))
                        .forEach(p -> p.setTurn(turns.getAndIncrement()));

                List<Player> ls = game.getPlayerList().stream().filter(p -> !p.getFinished()).collect(Collectors.toList());
                List<String> losers = ls.stream().map(Player::getName).collect(Collectors.toList());
                log.info("游戏结束,有身份牌的玩家 {} 败北", losers);
                game.setIsStarted(false);
                Runnable r = () -> dialog(StrUtil.format("游戏结束,有身份牌的玩家 {} 败北", losers));
                CommonService.runLater(r);
                return true;
            }

            if (winner.stream().allMatch(p -> p.getRole() == RoleEnum.SPECIAL_ONE)) {
                winner.stream().filter(p -> p.getTurn() == 0).findFirst().get().setWinEnum(WinEnum.REC_ONE);
                winner.stream().filter(p -> p.getTurn() == 1).findFirst().get().setWinEnum(WinEnum.REC_ONE);
                game.getPlayerList().stream().filter(p -> !p.getFinished()).forEach(p -> p.setWinEnum(WinEnum.GIV_ONE));

                AtomicInteger turns = new AtomicInteger(2);
                game.getPlayerList().stream()
                        .filter(p -> !p.getFinished()).sorted(Comparator.comparingInt(o -> o.getCards().size()))
                        .forEach(p -> p.setTurn(turns.getAndIncrement()));

                List<Player> ls = game.getPlayerList().stream().filter(p -> !p.getFinished()).collect(Collectors.toList());
                List<String> losers = ls.stream().map(Player::getName).collect(Collectors.toList());
                log.info("游戏结束,没身份牌的玩家 {} 败北", losers);
                game.setIsStarted(false);
                Runnable r = () -> dialog(StrUtil.format("游戏结束,没身份牌的玩家 {} 败北", losers));
                CommonService.runLater(r);
                return true;
            }
        }

        if (winner.size() == 3) {

            if (winner.stream().anyMatch(p -> p.getRole() == RoleEnum.SPECIAL_TWO)) {

                Player player = winner.stream().filter(p -> p.getRole() == RoleEnum.SPECIAL_TWO).findFirst().get();
                if (player.getTurn() == 1) {

                    winner.stream().filter(p -> p.getTurn() == 1).findFirst().get().setWinEnum(WinEnum.REC_ONE);
                    game.getPlayerList().stream().filter(p -> !p.getFinished()).forEach(p -> p.setWinEnum(WinEnum.GIV_ONE));

                    AtomicInteger turns = new AtomicInteger(2);
                    game.getPlayerList().stream()
                            .filter(p -> !p.getFinished()).sorted(Comparator.comparingInt(o -> o.getCards().size()))
                            .forEach(p -> p.setTurn(turns.getAndIncrement()));

                    List<Player> ls = game.getPlayerList().stream().filter(p -> !p.getFinished()).collect(Collectors.toList());
                    List<String> losers = ls.stream().map(Player::getName).collect(Collectors.toList());
                    log.info("游戏结束,没有身份牌的玩家 {} 败北", losers);
                    game.setIsStarted(false);
                    Runnable r = () -> dialog(StrUtil.format("游戏结束,没有身份牌的玩家 {} 败北", losers));
                    CommonService.runLater(r);
                    return true;

                } else if (player.getTurn() == 2) {

                    log.info("游戏结束,平局");
                    game.setIsStarted(false);
                    Runnable r = () -> dialog("游戏结束,平局");
                    CommonService.runLater(r);
                    return true;

                }
            }

            if (winner.stream().allMatch(p -> p.getRole() == RoleEnum.NORMAL)) {

                winner.stream().filter(p -> p.getTurn() == 0).findFirst().get().setWinEnum(WinEnum.REC_ONE);
                winner.stream().filter(p -> p.getTurn() == 1).findFirst().get().setWinEnum(WinEnum.REC_ONE);
                winner.stream().filter(p -> p.getTurn() == 2).findFirst().get().setWinEnum(WinEnum.REC_ONE);
                game.getPlayerList().stream().filter(p -> !p.getFinished()).forEach(p -> {
                    p.setWinEnum(WinEnum.GIV_THREE);
                    p.setTurn(3);
                });

                List<Player> ls = game.getPlayerList().stream().filter(p -> !p.getFinished()).collect(Collectors.toList());
                List<String> losers = ls.stream().map(Player::getName).collect(Collectors.toList());
                log.info("游戏结束,有身份牌的玩家 {} 败北", losers);
                game.setIsStarted(false);
                Runnable r = () -> dialog(StrUtil.format("游戏结束,有身份牌的玩家 {} 败北", losers));
                CommonService.runLater(r);
                return true;
            }

            if (winner.stream().filter(p -> p.getRole() == RoleEnum.SPECIAL_ONE).count() == 2) {

                Player player = winner.stream().filter(p -> p.getRole() == RoleEnum.NORMAL).findFirst().get();
                //平民-地主-地主-平民
                if (player.getTurn() == 0) {
                    log.info("游戏结束,平局");
                    game.setIsStarted(false);
                    Runnable r = () -> dialog("游戏结束,平局");
                    CommonService.runLater(r);
                    return true;
                }
                //地主-平民-地主-平民
                else if (player.getTurn() == 1) {

                    winner.stream().filter(p -> p.getTurn() == 0).findFirst().get().setWinEnum(WinEnum.REC_ONE);
                    game.getPlayerList().stream().filter(p -> !p.getFinished()).forEach(p -> {
                        p.setWinEnum(WinEnum.GIV_ONE);
                        p.setTurn(3);
                    });

                    List<Player> ls = game.getPlayerList().stream().filter(p -> p.getRole() == RoleEnum.NORMAL).collect(Collectors.toList());
                    List<String> losers = ls.stream().map(Player::getName).collect(Collectors.toList());
                    log.info("游戏结束,没有身份牌的玩家 {} 败北", losers);
                    game.setIsStarted(false);
                    Runnable r = () -> dialog(StrUtil.format("游戏结束,没有身份牌的玩家 {} 败北", losers));
                    CommonService.runLater(r);
                    return true;
                } else {
                    throw new RuntimeException("unknown error");
                }

            }

            if (winner.stream().filter(p -> p.getRole() == RoleEnum.NORMAL).count() == 2) {
                Player player = winner.stream().filter(p -> p.getRole() == RoleEnum.SPECIAL_ONE).findFirst().get();
                //地主-平民-平民-地主
                if (player.getTurn() == 0) {
                    log.info("游戏结束,平局");
                    game.setIsStarted(false);
                    Runnable r = () -> dialog("游戏结束,平局");
                    CommonService.runLater(r);
                    return true;
                }
                //平民-地主-平民-地主
                else if (player.getTurn() == 1) {

                    winner.stream().filter(p -> p.getTurn() == 0).findFirst().get().setWinEnum(WinEnum.REC_ONE);
                    game.getPlayerList().stream().filter(p -> !p.getFinished()).forEach(p -> {
                        p.setWinEnum(WinEnum.GIV_ONE);
                        p.setTurn(3);
                    });

                    List<Player> ls = game.getPlayerList().stream().filter(p -> p.getRole() == RoleEnum.SPECIAL_ONE).collect(Collectors.toList());
                    List<String> losers = ls.stream().map(Player::getName).collect(Collectors.toList());
                    log.info("游戏结束,有身份牌的玩家 {} 败北", losers);
                    game.setIsStarted(false);
                    Runnable r = () -> dialog(StrUtil.format("游戏结束,有身份牌的玩家 {} 败北", losers));
                    CommonService.runLater(r);
                    return true;
                } else {
                    throw new RuntimeException("unknown error");
                }
            }
        }

        return false;
    }

    private void dialog(String text) {
        Dialog<Pair<String, String>> dialog = new Dialog<>();
        dialog.initStyle(StageStyle.UTILITY);
        dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);

        DialogPane dialogPane = dialog.getDialogPane();

        Button btnCancel = (Button) dialogPane.lookupButton(ButtonType.CANCEL);
        btnCancel.setPrefWidth(40);
        btnCancel.setPrefHeight(20);
        btnCancel.setText("返回");
        btnCancel.setOnAction(e -> CommonService.jumpButtonEvent(discard, "main"));

        Button applyBtn = (Button) dialogPane.lookupButton(ButtonType.OK);
        applyBtn.setPrefWidth(40);
        applyBtn.setPrefHeight(20);
        applyBtn.setText("重玩");
        applyBtn.setOnAction(e -> {
            PokerGen.genNewCard();
            showCard(PokerGen.distributeCard());
            new Thread(() -> {
                try {
                    startGame();
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }).start();
        });

        Label label = new Label(text);
        label.setWrapText(true);
        label.setPrefWidth(150);
        label.setPrefHeight(100);

        dialog.getDialogPane().setContent(label);
        dialog.showAndWait();
    }
}
